import {shallowClone} from "./shallowClone";
import {toType} from "./toType";
import {getOwnAllProperty} from "../object/getOwnAllProperty";

/**
 * 深克隆，如果有多层，每层都要克隆
 * @param obj
 * @param cache
 */
export function deepClone(obj: unknown, cache = new Set()) {
    const type = toType(obj)
    // 如果不是对象或数组，按浅克隆处理 (没有嵌套)
    if(!/^object|array$/.test(type)) return shallowClone(obj)

    // 是数组|对象对象或其他引用类型
    /*--------------------------------------- -start- 避免对象自己套用自己，导致的无限递归 (let obj =  {a: 111} obj.obj = obj) ---------------------------------------*/
    // 如果缓存里已经有这个传入的值了，则直接返回这个传入的值，避免无限递归
    // obj -> 传入的值
    if(cache.has(obj)) return obj
    // 如果传入的值是引用数据类型，把它添加到缓存里，方便以后判断它有没有被处理过
    cache.add(obj)
    /*--------------------------------------- -end- ---------------------------------------*/

    let keys = getOwnAllProperty(obj),
        clone = {};
    if(/^array$/.test(type)) clone = []
    keys.forEach(key => {
        // 循环后拿到值，再递归处理多层的情况，并将以前的cache传入，递归后得到的值再复制一份
        (clone as any)[key] = deepClone((obj as any)[key], cache)
    })
    return clone
}